#ifndef GTL_FILE_SYSTEM_HEADER_GUARD
#define GTL_FILE_SYSTEM_HEADER_GUARD

#include <cstdio>
#include "gtlCompilerSpecific.h"
/*
#ifdef GTL_OS_WINDOWS
#include "gtlWindowsIncludes.h"
#elif GTL_OS_UNIX
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#endif
*/
/// TODO: Memory mapped files
/// http://msdn.microsoft.com/en-us/library/aa366537.aspx
/// http://msdn.microsoft.com/en-us/library/aa366761.aspx

namespace GTL
{
  namespace Files
  {
		inline FILE* fopen_safe(const char* filename, const char* mode)
		{
#ifdef GTL_OS_WINDOWS
			FILE* f = 0;
			fopen_s(&f, filename, mode);
			return f;
#elif GTL_OS_UNIX
			return fopen(filename, mode);
#endif
		}

		inline const char* GetFileExtension( const char* filename ) 
		{
			return strrchr(filename, '.')+1;
		}

		namespace Just
		{
			inline char* LoadEntireTextFile(const char* filename)
			{
        /// TODO: Cleanup this function; maybe make some cool inline functions
        /// that deal with files, but are platform specific
				FILE* f = fopen_safe(filename, "r");
				if (!f) return 0;

				fseek(f,0,SEEK_END);
				size_t fsize = ftell(f);
				rewind(f);

				char* tempString = new char[fsize+1];
				fsize = fread(tempString,1,fsize,f);
				tempString[fsize] = 0;
				fclose(f);

				return tempString;
			}
		}
		/*
		inline void AppendTextToFile(const char* filename, const char* format, ...) /// DONE
		{
			FILE *f = fopen(filename, "a");
			if (f) {
				va_list a;
				va_start(a, format);
				vfprintf(f, format, a);
				va_end(a);
				fclose(f);
			}
		}

    template <typename T>
    T** LoadArrayFromFile(const char* filename, size_t width, size_t height)
    {
      FILE* f = fopen(filename, "r");
      if (!f) return 0;
      T** buf = new T*[height];
      for (int i=0; i<height; i++)
      {
        buf[i] = new T[width];
        fread(buf[i], sizeof(T), width, f);
      }
      fclose(f);

      return buf;
    }

    template <typename T>
    T** Load2DArrayFromFile(const char* filename)
    {

    }

    inline int64_t GetFileSize(const char* filename)
    {
#ifdef GTL_OS_WINDOWS
      HANDLE file = CreateFile(filename, GENERIC_READ, 0, OPEN_EXISTING, 0, 0);
      if (file == INVALID_HANDLE_VALUE) return -1;

      LARGE_INTEGER fsize;
      if (!GetFileSizeEx(file,&fsize))
      {
        CloseHandle(file); 
        return -1;
      }

      CloseHandle(file);
      return fsize.QuadPart;
#elif GTL_OS_UNIX
      stat buf;
      int ret = stat(filename, &buf);
      if (ret == -1) return -1;
      return buf.st_size;
#endif
    }

    class CSTDIOFileWrapper
    {
    public:
      CSTDIOFileWrapper()
      {
        mFile = 0;
      }

      int Close()
      {
        int result = 0;
        if (mFile)
          result = fclose(mFile);
        mFile = 0;

        return result;
      }

      bool IsOpen() const
      {
        return !!mFile;
      }

      FILE* GetFilePointer() { return mFile; }
      const FILE* GetFilePointer() const { return mFile; }

      int64_t GetFileSize()
      {
        if (!mFile) return -1;

        size_t curPos = ftell(mFile);
        fseek(0, SEEK_END);
        int64_t size = ftell(mFile);
        fseek(curPos, SEEK_SET);

        return size;
      }

      int EOF() { if (mFile) return feof(mFile); else return 0; }
      int Error() { if (mFile) return ferror(mFile); else return 0; }
      int Flush() { if (mFile) return fflush(mFile); else return -1; }

      int GetCharacter()
      {
        if (mFile) return fgetc(mFile); else return -1;
      }

      ~CSTDIOFileWrapper()
      {
        Close();
      }

    private:
      FILE* mFile;
      CSTDIOFileWrapper(const CSTDIOFileWrapper& other);
      CSTDIOFileWrapper& operator=(const CSTDIOFileWrapper& other);
    };
		
		*/
  }
}

#endif